use glam::*;
use std::rc::Rc;

use crate::grid;
use crate::logic;
use crate::view::*;

mod cursor;
pub use cursor::*;

#[derive(Clone, Copy)]
pub struct Floor {
    pub cursor: Cursor,
}

impl Floor {
    pub fn next_frame(self, next_frame_number: FrameNumber) -> Self {
        Floor {
            cursor: self.cursor.next_frame(next_frame_number),
        }
    }
}

#[derive(Clone)]
pub struct FloorExplorer {
    pub layout: FloorExplorerLayout,
    pub floor: Floor,
    pub logic_floor: Rc<logic::Floor>,
}

impl FloorExplorer {
    pub fn new(dim: Vec2, logic_floor: Rc<logic::Floor>) -> Self {
        let size = logic_floor.size;
        Self {
            layout: FloorExplorerLayout::new(dim),
            logic_floor,
            floor: Floor {
                cursor: Cursor::at(grid::Position::new(size, 0, 0)),
            },
        }
    }

    pub fn next_frame(&self, next_frame_number: FrameNumber) -> Self {
        Self {
            floor: self.floor.next_frame(next_frame_number),
            ..self.clone()
        }
    }

    pub fn handle_inputs(
        &self,
        frame_number: FrameNumber,
        inputs: std::collections::hash_set::HashSet<Input>,
    ) -> Self {
        if inputs.contains(&Input::Up) {
            Self {
                floor: Floor {
                    cursor: self
                        .floor
                        .cursor
                        .move_offset(frame_number, grid::PositionOffset::UP),
                },
                ..self.clone()
            }
        } else if inputs.contains(&Input::Down) {
            Self {
                floor: Floor {
                    cursor: self
                        .floor
                        .cursor
                        .move_offset(frame_number, grid::PositionOffset::DOWN),
                },
                ..self.clone()
            }
        } else if inputs.contains(&Input::Left) {
            Self {
                floor: Floor {
                    cursor: self
                        .floor
                        .cursor
                        .move_offset(frame_number, grid::PositionOffset::LEFT),
                },
                ..self.clone()
            }
        } else if inputs.contains(&Input::Right) {
            Self {
                floor: Floor {
                    cursor: self
                        .floor
                        .cursor
                        .move_offset(frame_number, grid::PositionOffset::RIGHT),
                },
                ..self.clone()
            }
        } else {
            self.clone()
        }
    }
}

#[derive(Clone, Copy)]
pub struct Frame {
    pub pos: Vec2,
    pub dim: Vec2,
}

#[derive(Clone, Copy)]
pub struct FloorExplorerLayout {
    pub dim: Vec2,
    pub floor_frame: Frame,
    pub detail_frame: Frame,
}

impl FloorExplorerLayout {
    pub fn new(dim: Vec2) -> Self {
        let frame_top = dim.y / 4.0;
        let frame_left = dim.x / 4.0;
        let frame_width = dim.x / 2.0;
        let frame_height = dim.y / 2.0;

        Self {
            dim,
            floor_frame: Frame {
                pos: vec2(frame_left, frame_top),
                dim: vec2(frame_width, frame_height),
            },
            detail_frame: Frame {
                pos: vec2(0.0, 0.0),
                dim: vec2(0.0, 0.0),
            },
        }
    }
}
